﻿using System.Runtime.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Net;
using System.IO;
using System.Web;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;



namespace H2O
{

    /// <summary>
    /// 
    /// 1自动启动
    /// 2保存和读取参数
    /// 3确定在线（如果不在线就看看是否拨号，需要拨号就拨号，否则sheep并报错，等会再试）
    /// 4登录验证用户名密码，获得token
    /// 5使用token获取脚本
    /// 6执行脚本
    /// 7循环获取脚本（如果token失效，就跳到跳到验证用户名密码这一环节）
    /// 8脚本执行完成后
    /// 9判断是否拨号，如果拨号就断线
    /// 10跳到确定在线环节
    ///  
    /// </summary>
    public partial class Main : Form
    {
        static string LOGIN_ADDR = "http://api.yunso.cn/api/login?u={username}&p={password}";
        static string SCRIPT_ADDR = "http://api.yunso.cn/api/?t={token}&ip={ip}&ipbest={ipbest}";
        static string UPDATE_ADDR = "http://api.yunso.cn/api/update";


        static string REDIAL = "ADSL";
        static int REDIAL_MAX = 10; //错误重播的次数




        RASDisplay ras;
        BrowserPipe browserPipe;
        bool loopControl = true;
        int lastTime = 0;
        string token = "";
        int ipbest = -1;


        public Main()
        {
            InitializeComponent();
            ras = new RASDisplay();
            browserPipe = new BrowserPipe(this);

#if DEBUG

#else
            this.Shown += new System.EventHandler(this.Main_Shown);
#endif
            //2保存和读取参数
            this.loadConfig();
        }
        /// <summary>
        /// 
        /// 初始化一些属性和配置
        /// </summary>
        private void loadConfig()
        {
            this.username.Text = Helper.readINI("username");
            this.password.Text = Helper.readINI("password");
            this.isDial.Checked = Helper.readINI("isDial") == "true";
        }
        /// <summary>
        /// 写入配置信息
        /// </summary>
        private void saveConfig()
        {
            Helper.writeINI("username", this.username.Text);
            Helper.writeINI("password", this.password.Text);
            Helper.writeINI("isDial", this.isDial.Checked.ToString());
        }

        /// <summary>
        /// 登录方法
        /// </summary>
        private void login()
        {
            //token
            /// 3，验证，不通过，进入2
            /// 4.获得脚本

            JSONStat result = getLoginJSON();

            if (result.success)
            {
#if DEBUG
                log("登录密码：" + result.token);
#endif
                token = result.token;
                log("登录成功！");
            }
            else
            {
                loopControl = false;
                log("登录失败，用户名密码不正确！");
            }

        }

        private void Disconnect()
        {
            if (this.isDial.Checked)
            { ras.Disconnect(); }
        }
        private bool redial()
        {

            /////////////清理数据////////////////////////////////  
            log("开始清理本地Cookies.");
            Helper.clear();
            ////////////////////////////////////////////////////
            if (this.isDial.Checked)
            {
                log("开始拨号...");
                for (int i = 0; i <= REDIAL_MAX; i++)
                {
                    if (!loopControl)
                    {
                        break;
                    }
                    if (ras.Connected() == IntPtr.Zero)
                    {
                        if (i == REDIAL_MAX)
                        {
                            return false;
                        }
                        log("第" + (i + 1) + "次拨号.");
                        //没有拨号成功 ，重拨
                        int r = ras.Connect(REDIAL);
                        //拨号失败等待30秒...
                        waitOfSecond(30);
                    }
                    else
                    {
                        log("拨号成功!");
                        break;
                    }
                }
            }
            else
            {
                if (ras.Connected() == IntPtr.Zero)
                {
                    log("不能上网!");
                    waitOfSecond(60);
                    return false;
                }
            }
            return true;
        }

        /// 1自动启动
        /// 2保存和读取参数
        /// 3确定在线（如果不在线就看看是否拨号，需要拨号就拨号，否则sheep并报错，等会再试）
        /// 3.5检查更新
        /// 4登录验证用户名密码，获得token
        /// 5使用token获取脚本
        /// 6执行脚本
        /// 7循环获取脚本（如果token失效，就跳到跳到验证用户名密码这一环节）
        /// 8脚本执行完成后
        /// 9判断是否拨号，如果拨号就断线
        /// 10跳到确定在线环节
        /// 
        private void startApp()
        {
            loopControl = true;
            this.status.Text = "已启动";
            // this.tabPage1.FindForm 
            this.tabControl1.SelectedIndex = 1;
            //2保存和读取参数
            saveConfig();

            while (loopControl)
            {
                try
                {
                    this.logs.Text = "";
                    /// 3确定在线（如果不在线就看看是否拨号，需要拨号就拨号，否则sheep并报错，等会再试）
                    if (!redial()) { continue; }

                    /// 3.5检查更新
                    updateVersion();

                    //4登录验证用户名密码，获得token
                    if (token == "")
                    {
                        login();
                    }
                    /// 5使用token获取脚本
                    /// 6执行脚本
                    if (!loopControl)
                    {
                        break;
                    }

                    /// 7循环获取脚本（如果token失效，就跳到跳到验证用户名密码这一环节）
                    JSONScript jsonScript = getJson();
                    ipbest = jsonScript.ipbest;
                    token = jsonScript.token;

                    jsonScript.Parse();
                    log("Scripts Total : " + jsonScript.scripts.Count + " Time Now = " + DateTime.Now.ToLongTimeString());
                    for (int i = 0; i < jsonScript.scripts.Count; i++)
                    {
                        if (!loopControl)
                        {
                            break;
                        }
                        log("执行脚本 : " + (i + 1));

                        browserPipe.process((List<BrowserAction>)jsonScript.scripts[i]);

                        Application.DoEvents();
                    }

                    /// 8脚本执行完成后
                    /// 9判断是否拨号，如果拨号就断线
                    /// 10跳到确定在线环节
                    Disconnect();
                }
                catch (Exception e)
                {
                    log(e.ToString(), 3);

                }
                GC.Collect();
            }

        }

        /// <summary>
        /// 停止方法
        /// </summary>
        private void stopApp()
        {
            loopControl = false;
            this.status.Text = "已停止.";
        }
        /// <summary>
        /// 获得脚本json数据
        /// </summary>
        /// <returns></returns>
        private JSONStat getLoginJSON()
        {

            string verify = LOGIN_ADDR;
            verify = verify.Replace("{username}", this.username.Text);
            verify = verify.Replace("{password}", this.password.Text);


#if DEBUG
            log("Login URL = " + verify);
#endif

            string jsinstr = Helper.SendRequest(verify);

#if DEBUG
            log("JSON String = " + jsinstr);
#endif
            if (jsinstr == "")
            {
                return new JSONStat();
            }
            JSONStat jsonObj = new JSONStat();

            System.Runtime.Serialization.Json.DataContractJsonSerializer _Json =
                new System.Runtime.Serialization.Json.DataContractJsonSerializer(jsonObj.GetType());

            byte[] _Using = System.Text.Encoding.UTF8.GetBytes(jsinstr);

            System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(_Using);
            _MemoryStream.Position = 0;

            return (JSONStat)_Json.ReadObject(_MemoryStream);
        }
        /// <summary>
        /// 获得脚本json数据
        /// </summary>
        /// <returns></returns>
        private JSONScript getJson()
        {
            string verify = SCRIPT_ADDR;
            verify = verify.Replace("{token}", token);
            string ip = ras.getIPAddress();
            if (ip == null)
            {
                verify = verify.Replace("{ip}", "");
            }
            else
            {
                verify = verify.Replace("{ip}", ras.getIPAddress());
            }
            if (ipbest >= 0)
            {
                verify = verify.Replace("{ipbest}", ipbest + "");
            }
            else
            {
                verify = verify.Replace("{ipbest}", "");
            }
            //static string SCRIPT_ADDR = "http://api.yunso.cn/api/?t={token}&ip={ip}&ipbest={ipbest}";

#if DEBUG
            log("Login URL = " + verify);
#endif

            string jsinstr = Helper.SendRequest(verify);

#if DEBUG
            log("JSON String = " + jsinstr);
#endif
            if (jsinstr == "")
            {
                return new JSONScript();
            }

            JSONScript jsonObj = new JSONScript();

            System.Runtime.Serialization.Json.DataContractJsonSerializer _Json =
                new System.Runtime.Serialization.Json.DataContractJsonSerializer(jsonObj.GetType());

            byte[] _Using = System.Text.Encoding.UTF8.GetBytes(jsinstr);

            System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(_Using);
            _MemoryStream.Position = 0;

            return (JSONScript)_Json.ReadObject(_MemoryStream);
        }

        private int timeout = 500;
        /// <summary>
        /// 等待几秒种
        /// </summary>
        /// <param name="second"></param>
        private void waitOfSecond(int second)
        {

            second = second * (1000 / timeout);
            for (int x = 0; x < second && loopControl; x++)
            {
                Application.DoEvents();
                System.Threading.Thread.Sleep(timeout);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <param name="level"></param>
        public void log(string t, int level)
        {
            log(t);
        }
        public void log(string t)
        {
            this.logs.AppendText(t + "\r\n");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            browserPipe.process(Helper.executeScript(Regex.Replace(this.clicktest.Text, @"\r\n", "||")));
        }

        private void updateVersion()
        {
            string v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
            //MessageBox.Show("IE Version " + v);
            /////////////////////////
            if (lastTime == 0 || lastTime != DateTime.Now.Hour)
            {
                log("检查更新...");
                string[] str = Helper.SendRequest(UPDATE_ADDR).Split('|');

                if (str.Count() > 1 && str[1].StartsWith("http"))
                {
                    if (ShouldUpdate(str[0], v))
                    {
                        log("更新中需要几分钟时间，请稍等...");
                        System.Diagnostics.Process.Start(Application.StartupPath + @"\AutoUpdater.exe",
                            str[1]);
                        this.Close();
                    }
                }

            }

            lastTime = DateTime.Now.Hour;

        }

        private bool ShouldUpdate(string serverVersion, string localVersion)
        {
            if (!string.IsNullOrEmpty(serverVersion) && !string.IsNullOrEmpty(localVersion))
            {
                return serverVersion.CompareTo(localVersion) > 0;
            }
            return true;
        }

        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.stopApp();
            if (ras != null)
            {
                //ras.Disconnect();
                //if (ras.Connected() == IntPtr.Zero) ras.Connect(this.connName.Text);
                ras = null;
            }
            if (browserPipe != null)
            {
                browserPipe = null;
            }
            Helper.clear();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            MessageBox.Show("IE Version " + Helper.getIEVersion());
        }

        private void button6_Click(object sender, EventArgs e)
        {
            this.logs.Text = "";
        }

        private void Main_Shown(object sender, EventArgs e)
        {
            this.startApp();

        }

        private void stop_Click(object sender, EventArgs e)
        {
            this.stopApp();
        }

        private void startup_Click(object sender, EventArgs e)
        {
            this.startApp();
        }


    }
    public class JSONScript
    {
        public int ipbest = -1;
        public string task = "";
        public string token = "";

        public ArrayList scripts = new ArrayList();
        public JSONScript()
        {

        }
        public JSONScript(int i, string t, string tt)
        {
            ipbest = i;
            task = t;
            token = tt;
        }

        public void Parse()
        {
            if (task != "")
            {
                string[] scs = Regex.Split(task, @"\|\|", RegexOptions.IgnoreCase);
                foreach (string s in scs)
                {
                    scripts.Add(executeScript(s));
                }
            }
        }
        private List<BrowserAction> executeScript(string s)
        {
            string[] webactions = Regex.Split(s, @"\|", RegexOptions.IgnoreCase);

            List<BrowserAction> result = new List<BrowserAction>();

            foreach (string obj in webactions)
            {
                string[] wa = obj.Split(',');
                //println "${id}  ${wa[0]} ${wa[1]} ${wa.size() > 2? wa[2] :''}" 
                if (wa.Length > 1)
                {
                    BrowserAction ba = new BrowserAction(wa[0].Trim(), wa[1].Trim());
                    if (wa.Length > 2)
                    {
                        if (ba.action == "input")
                        {
                            ba.value = wa[2].Trim();
                        }
                        else if (ba.action == "click")
                        {
                            ba.random = Int16.Parse(wa[2].Trim());
                        }
                        else if (ba.action == "iframead")
                        {
                            ba.offset = new Coordinate(Int16.Parse(wa[2].Trim().Split('|')[0]),
                             Int16.Parse(wa[2].Trim().Split('|')[1])); 
                        }
                    }
                    result.Add(ba);
                }
                Application.DoEvents();
            }
            return result;
        }
    }


    public class JSONStat
    {
        public Boolean success = false;
        public string token = "";
        public JSONStat()
        {

        }
        public JSONStat(Boolean a, string t)
        {
            success = a;
            token = t;
        }
    }
}
